#ifndef _HASHED_STRING_H
#define _HASHED_STRING_H

#include <string>
#include <cassert>
#include "StringUtilities.h"

class HashedString
{
public:		HashedString( char const * const aString )
				: _ident( HashName( aString ) )
				, _identString( GetToLower(aString) )
			{
			}


			HashedString( unsigned long const aHash )
				: _ident( reinterpret_cast< void * >( aHash ) )
				, _identString( "Hash from unsigned long" )
			{
			}

			HashedString()
				:_ident( HashName( "NOT_SET" ) )
				, _identString( "NOT_SET" )
			{
			}

			unsigned long getIdent( void ) const 
			{
				return reinterpret_cast< unsigned long >( _ident );
			}


			std::string const &getString( void ) const 
			{
				return _identString;
			}


			bool operator < ( HashedString const &aHashedString ) const 
			{
#ifdef _DEBUG
				if(getIdent() == aHashedString.getIdent())
				{
					assert(getString() == aHashedString.getString() && "Possible hash conflict detected!");
				}
#endif
				return ( getIdent() < aHashedString.getIdent() );

			}


			bool operator == ( HashedString const &aHashedString ) const 
			{
				return ( getIdent() == aHashedString.getIdent() );
			}


			static void *HashName( const char *aString ) 
			{
				unsigned long BASE = 65521L;
				unsigned long NMAX = 5552;

#define DO1( buf, i )	{ s1 += tolower( buf[i] ); s2 += s1; }
#define DO2( buf, i )	DO1( buf, i ); DO1( buf, i + 1 );
#define DO4( buf, i )	DO2( buf, i ); DO2( buf, i + 2 );
#define DO8( buf, i )	DO4( buf, i ); DO4( buf, i + 4 );
#define DO16( buf )		DO8( buf, 0 ); DO8( buf, 8 );

				if( aString == 0 ) 
				{
					return 0;
				}

				unsigned long	s1 = 0,
					s2 = 0;

				for( size_t len = strlen( aString ); len > 0; ) 
				{
					unsigned long k = len < NMAX ? len : NMAX;

					len -= k;

					while( k >= 16 ) 
					{
						DO16( aString );
						aString += 16;
						k -= 16;
					}

					if( k != 0 ) 
					{
						do 
						{
							s1 += tolower(*aString++);
							s2 += s1;
						} while( --k );
					}

					s1 %= BASE;
					s2 %= BASE;
				}

#pragma warning( push )
#pragma warning( disable: 4312 )

				return reinterpret_cast< void * >( ( s2 << 16 ) | s1 );

#pragma warning( pop )
#undef DO1
#undef DO2
#undef DO4
#undef DO8
#undef DO16
			}


private:	void		*_ident;
			std::string	_identString;
};

#endif

